using System;
using System.Configuration;
using System.Web;
using System.Xml;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington	
	Started:	2006-03-08	
	Status:		release	
	Version:	2.0.0
	Buidl:		20070524
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/
	
/*	-----------------------------------------------------------------------	
	Development Notes:
	==================
	20070524:	Modification for .Net 2.0
	-----------------------------------------------------------------------	*/
	
namespace umlungu.engineX.blogX {
	/// <summary>Description of the enumeration</summary>
	public enum x_debugStatus {
		/// <summary>No debugging</summary>
	    off = 0,
		/// <summary>Debugging on</summary>
	    on = 1,
		/// <summary>Debugging on, output to file</summary>
	    file = 2,
		/// <summary>Debugging on, output to file (no debugging display)</summary>
	    fileonly = 3
	}
	/// <summary>
	/// The x_debug class is a utility class to handle debugging functionality.
	/// <para>This clas does the following:</para>
	/// <para>- sets status via the debug flag</para>
	/// <para>- writes debugging info to a file</para>
	/// </summary>
	public class x_debug {
		#region Invisible properties
		private string filepath;
		private XmlDocument debugXml;
		private const string id = "debugX";
		private DateTime starttime;
		#endregion

		#region Constants
		private const string CONFIG_ROOT = "BlogX";
		private const string CONFIG_ELEM = "DebugX";
		#endregion

		#region Visible properties
		private x_debugStatus status;
		/// <summary>Enumeration to indicate debugging status</summary>
		/// <value>May be set to 'off', 'on', 'file' or 'fileonly'</value>
		public x_debugStatus Status {
			get { return status; }
			set { status = value; }
		}
		/// <summary>Flag to indicate if debugging enabled</summary>
		/// <value>True if status is on, file or fileonly, else False</value>
		public bool Enabled {
			get { return (status == x_debugStatus.on || status == x_debugStatus.file); }
		}
		/// <summary>Flag to indicate if debugging enabled</summary>
		/// <value>True if status is on, file or fileonly, else False</value>
		public bool Tracking {
			get { return (status == x_debugStatus.file || status == x_debugStatus.fileonly); }
		}
		private XmlElement root {
			get { return (XmlElement)debugXml.DocumentElement.SelectSingleNode(String.Concat("/" + id)); }
		}
		#endregion

		#region Constructors/Destructors
		/// <overloads>Constructor</overloads>
		/// <summary>Default constructor</summary>
		public x_debug() {
			initialise(false, "");
		}
		/// <summary>Common constructor</summary>
		/// <param name="path">FilePath to the debugging file</param>
		public x_debug(string path) {
			x_config config = new x_config();
			string state = config.Value(String.Concat(CONFIG_ROOT, "/", CONFIG_ELEM, "/@site"));
			initialise(state, path);
		}
		/// <summary>Common constructor</summary>
		/// <param name="path">FilePath to the debugging file</param>
		public x_debug(string path, DateTime start) {
			x_config config = new x_config();
			string state = config.Value(String.Concat(CONFIG_ROOT, "/", CONFIG_ELEM, "/@site"));
			initialise(state, path, start);
		}
		/// <summary>Common constructor</summary>
		/// <param name="state">Indicates if debugging is on or off</param>
		/// <param name="path">FilePath to the debugging file</param>
		public x_debug(string state, string path) {
			initialise(state, path);
		}
		/// <summary>Common constructor</summary>
		/// <param name="on">Indicates if debugging is on or off</param>
		/// <param name="path">FilePath to the debugging file</param>
		public x_debug(bool on, string path) {
			initialise(on, path);
		}
		/// <summary>Common constructor</summary>
		/// <param name="state">Indicates debugging status</param>
		/// <param name="path">FilePath to the debugging file</param>
		public x_debug(x_debugStatus state, string path) {
			status = state;
			initialise(state, path);
		}
		#endregion

		#region Public methods
		/// <overloads>Writes a debug spoor to the debug document</overloads>
		/// <summary>
		/// Simple spoor
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		public void Spoor(string name) {
			if (!Tracking)
				return;
			addTime(root.AppendChild(debugXml.CreateElement(name)));
		}
		/// <summary>
		/// Spoor of name and xml document
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		/// <param name="xmldoc">An xml document to be written as a cdata element</param>
		public void Spoor(string name, XmlDocument xmldoc) {
			if (!Tracking)
				return;
			XmlNode newnode = root.AppendChild(debugXml.CreateElement(name));
			if (xmldoc == null)
				newnode.InnerText = "null";
			else
				//newnode.AppendChild(debugXml.CreateCDataSection(xmldoc.OuterXml));
				newnode.AppendChild(debugXml.ImportNode(xmldoc.DocumentElement, true));
			addTime(newnode);
		}
		/// <summary>
		/// Spoor of name and xml node
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		/// <param name="node">An node to be imported</param>
		public void Spoor(string name, XmlNode node) {
			if (!Tracking)
				return;
			XmlNode newnode = root.AppendChild(debugXml.CreateElement(name));
			if (node == null)
				newnode.InnerText = "null";
			else
				//newnode.AppendChild(debugXml.CreateCDataSection(node.OuterXml));
				newnode.AppendChild(debugXml.ImportNode(node, true));
			addTime(newnode);
		}
		/// <summary>
		/// Spoor of name and a single parameter
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		/// <param name="arg">A single parameter</param>
		public void Spoor(string name, string arg) {
			if (!Tracking)
				return;
			XmlNode spoorel = root.AppendChild(debugXml.CreateElement(name));
			spoorel.InnerText = arg;
			addTime(spoorel);
		}
		/// <summary>
		/// Spoor of name and a set of name-value pairs
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		/// <param name="args">Brief description of the parameter</param>
		public void Spoor(string name, params string[] args) {
			if (!Tracking)
				return;
			XmlElement spoorarg, spoorel = (XmlElement)root.AppendChild(debugXml.CreateElement(name));
			for (int i=0; i<args.Length; i=i+2) {
				spoorarg = (XmlElement)spoorel.AppendChild(debugXml.CreateElement(args[i]));
				spoorarg.InnerText = args[i+1];
			}
			addTime(spoorel);
		}
		/// <summary>
		/// Spoor of name and an x_exception
		/// </summary>
		/// <param name="name">The name of the debug spoor (typically the method name)</param>
		/// <param name="except">The x_exception</param>
		public void Spoor(string name, x_exception except) {
			if (!Tracking)
				return;
			XmlElement spoorel = root.AppendChild(debugXml.CreateElement(name)) as XmlElement;
			spoorel.InnerText = except.Message;
			spoorel.SetAttribute("code", except.Code);
		}
		/// <summary>
		/// Description of this method
		/// </summary>
		public void Save() {
			if (Tracking)
				debugXml.Save(filepath);
		}
		#endregion
		
		#region Protected methods
		#endregion
		
		#region Private methods
		private void initialise(string path, DateTime start) {
			if (Tracking) {
				debugXml = new XmlDocument();
				debugXml.LoadXml(String.Concat("<", id, "/>"));
				filepath = path;
			}
			starttime = start;
		}
		private void initialise(bool on, string path) {
			status = (on)? x_debugStatus.on : x_debugStatus.off;
			initialise(path, DateTime.Now);
		}
		private void initialise(x_debugStatus state, string path) {
			status = state;
			initialise(path, DateTime.Now);
		}
		private void initialise(string state, string path) {
			initialise(state, path, DateTime.Now);
		}
		private void initialise(string state, string path, DateTime start) {
			switch(state) {
				case "file":		status = x_debugStatus.file;		break;
				case "fileonly":	status = x_debugStatus.fileonly;	break;
				case "true":
				case "yes":			status = x_debugStatus.on;			break;
				case "no":
				default:			status = x_debugStatus.off;			break;
			}
			initialise(path, start);
		}
		/// <summary>
		/// Mark placed in xml as attribute of node
		/// </summary>
		private void addTime(XmlNode node) {
			addTime((XmlElement)node);
		}
		private void addTime(XmlElement elem) {
			DateTime endtime = DateTime.Now;
			TimeSpan timetaken = endtime - starttime;
			string thistime = timetaken.TotalSeconds.ToString();
			elem.SetAttribute("time", thistime);
			//elem.SetAttribute("ticks", endtime.Ticks.ToString());
		}
		#endregion
	}
}
